package shard

import (
	"fmt"
	"hash"
	"hash/adler32"
	"hash/crc32"
	"hash/fnv"
	"sync"
)

type smapShard struct {
	l        uint32
	shards   []sync.Map
	hashFunc func(string) uint32
	hs       hash.Hash32
}

func NewSmapShard(shardNums uint) Shards {
	sd := &smapShard{
		l:      uint32(shardNums),
		shards: make([]sync.Map, shardNums),
	}
	sd.UseFnvHash()
	return sd
}

func (sd *smapShard) UseFnvHash() {
	sd.hs = fnv.New32()
	sd.hashFunc = func(s string) uint32 {
		sd.hs.Reset()
		sd.hs.Write([]byte(s))
		return sd.hs.Sum32() % sd.l
	}
}

func (sd *smapShard) UseAdler32Hash() {
	sd.hs = adler32.New()
	sd.hashFunc = func(s string) uint32 {
		sd.hs.Reset()
		sd.hs.Write([]byte(s))
		return sd.hs.Sum32() % sd.l
	}
}

func (sd *smapShard) UseCrc32Hash() {
	sd.hs = crc32.New(crc32.IEEETable)
	sd.hashFunc = func(s string) uint32 {
		sd.hs.Reset()
		sd.hs.Write([]byte(s))
		return sd.hs.Sum32() % sd.l
	}
}

func (sd *smapShard) SetHashFunc(hf func(string) uint32) {
	sd.hashFunc = hf
}

func (sd *smapShard) Get(userId uint) (any, bool) {

	return sd.shards[sd.hashFunc(fmt.Sprintf("%d", userId))].Load(userId)
}

func (sd *smapShard) Set(userId uint, value any) {
	sd.shards[sd.hashFunc(fmt.Sprintf("%d", userId))].Store(userId, value)
}

func (sd *smapShard) Delete(userId uint) {
	sd.shards[sd.hashFunc(fmt.Sprintf("%d", userId))].Delete(userId)
}
